Overview of Data
The purpose of this dataset was to help find predictors of diabetes.
The goal is to help medical professionals identify patients with
potential risk factors of diabetes.The dataset contains information on
patient demographics such as age and gender, as well as medical
information including blood glucose levels and hypertension. The
observations in this dataset were obtained from research studies and
healthcare institutions. The dataset was obtained via Kaggle.
Mustafa, T. Z. (2021). Diabetes Prediction Dataset. Kaggle.
https://www.kaggle.com/datasets/iammustafatz/diabetes-prediction-dataset
The dataset consists of 8 predictor variables for diabetes: ‘gender’
the patient’s gender as male or female. ‘age’ the age of the patient in
years. ‘hypertension’ yes or no, on whether the patient has
hypertension. ‘heart disease’ yes or no, on whether the patient has
heart disease. ‘smoking history’ the patient’s smoking history indicated
as never, no info, current, former or not current. ‘bmi’ the patient’s
body mass index (kg/m**2). ‘HbA1c level’ the patient’s average blood
sugar level over the past 2-3 months (%). ‘blood glucose level’ amount
of blood sugar in the patient’s blood (mg/dL).
#load in dataset
data <-read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/diabetes_prediction_dataset.csv')
diabetesd<-data
#change heart disease, diabetes and hypertension to 1 and 0 for easier use in MICE.
data$diabetes <- recode(data$diabetes, "1"="Yes", "0"="No")
data$hypertension <- recode(data$hypertension, "1"="Yes", "0"="No")
data$heart_disease <- recode(data$heart_disease, "1"="Yes", "0"="No")
#plot interaction between diabetes and hypertension.
ggplot(data, aes(x = hypertension, fill = diabetes)) +
geom_bar(position = "dodge") + # Use "stack" for a stacked bar chart
labs (title="Risk of Diabetes by Hypertension", x="Hypertension", y= "Frequency",
fill= "Diabetes")
Comparison of Two Categorical Variables
The purpose of this graph is to show the relationship between having
hypertension and diabetes. For this graph, I changed the values of 1 in
both the diabetes and hypertension variable to “Yes” and the value 0 to
“No.” These integers were meant to represent categorical variables with
1 correlating to being positive for hypertension or diabetes and 0
correlating to being negative to hypertension or diabetes. Based on our
graph, we can see that there is no correlation between having diabetes
and having hypertension, with most patients within our sample having
neither diabetes or hypertension. Thus, hypertension would not be a good
predictor of diabetes within patients.
interact = ggplot(data, aes(x =blood_glucose_level , y = HbA1c_level, group = diabetes, color = diabetes)) +
geom_line(size = 1) + # Lines representing interaction
geom_point(size = 2) + # Points for data
labs(
title = "Interaction of Blood Glucose and HbA1c Levels",
x = "Blood Glucose Level",
y = "HbA1c Level",
color = "Presence of Diabetes"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.text = element_text(size = 12),
legend.position = "top"
)
interact
Comparison of Two Numerical Variables
The two variables being compared here are Blood Glucose Level and
HbA1c Level. HbA1cc is a shortened term for hemoglobin A1c. Hb1Ac level
is a measure of average blood sugar levels over 2-3 months and is
measured in %. Blood glucose level is the amount of blood sugar in a
patients blood at a given time. Our plot shows a correlation between
high levels in HbA1c and blood glucose levels and it’s relationship with
diabetes. This plot suggests patients with high levels of HbA1c and
blood glucose levels are at high risk for diabetes.
#plot of a numerical and categorical variable
boxplot(data$age ~ data$diabetes,
xlab="Patient Age",
ylab="Presence of Diabetes",
col = c("skyblue", "purple"),
main="Visualization of Diabetes by Age",
cex.main = 1.1,
col.main = "navy")
Comparison of a Numerical and Categorical Variables
This chart shows the relationship between age and diabetes diagnosis.
This chart shows that as patients grow older they are at higher risk for
diabetes. This would make age a predictor for diabetes, with the average
age for those without diabetes being 40 years and 60 years for those
with diabetes. However, we can see that we do have a few outliers for
those with diabetes with some patients being diagnosed at 20 or younger.
This could be from the population of people with Type I diabetes which
is usually diagnosed in patients under 20. Our dataset does not
distinguish between type I and type II diabetes.
Conclusion for Comparison of Variables
Diabetes can be predicted using age, blood glucose levels, and HbA1c
levels in patients. However, our results showed hypertension is not a
good predictor of diabetes. Based on our findings, it would be
interesting to look at factors that occur once a patient becomes older
that could lead to diabetes at an older age. As well, diet could be
another factor to look into, such as grams of sugar consumed on a daily
or weekly basis, to see if sugar consumption can predict diabetes.
Another important thing to analyze in future studies would be Type I
versus Type II diabetes, as it could be the reason for some of the
outliers in the boxplot.
Overview of Missing Variables
An important step in data analysis for machine learning is handling
missing values. Missing values in a dataset can occur for many reasons,
but not limited to non-response in surveys, participants leaving the
study, data entry errors and system limitations. If missing values are
not addressed, models can become biased and accuracy of the anaylysis
can decrease. This section examines different imputation strategies to
effectively handle missing values.
The imputation methods we will examine include:
Replacement Imputation for Categorical Features: Mode imputation and
KNN-based imputation.
Regression-based Imputation for Numerical Features: Predictive
modeling to estimate missing values.
Multiple Imputation: Advanced methods such as MICE to improve
robustness.
# create random observation ID and replace the corresponding obs with missing
ltr.missing.id <- sample(1:1000, 50, replace = FALSE)
gpa.missing.id <- sample(1:1000, 15, replace = FALSE)
diabetesd$bmi[ltr.missing.id] <- NA
diabetesd$heart_disease[gpa.missing.id] <- NA
diabetesd$smoking_history[diabetesd$smoking_history == "No Info"] <- NA
Mode Imputation for Categorical Variables
In this method, missing variables are replaced with the most frequent
category of the corresponding variable. Mode imputation ensures
consistency and works well when missing values are randomly distributed.
Below, mode imputation is used on the variable, heart disease, which is
1 if the patient has heart disease and 0 if the patient does not have
heart disease.The variable smoking history had current, former, no info,
never, and ever as possible values. No Info indicates that we do not
have information on the participant’s smoking history and will be
treated as a missing values.
diabetesd <-diabetesd
# Function to impute mode
Mode <- function(x) {
ux <- unique(na.omit(x)) # Remove NAs before computing mode
tab <- tabulate(match(x, ux))
mode_value <- ux[which.max(tab)]
# Ensure mode_value is of the same type as x
if (is.factor(x)) {
return(factor(mode_value, levels = levels(x)))
} else if (is.character(x)) {
return(as.character(mode_value))
} else {
return(as.numeric(mode_value))
}
}
#apply mode imputation
value_imputed <- data.frame(
original = diabetesd$heart_disease,
original2=diabetesd$smoking_history,
imputed_modehd = replace(diabetesd$heart_disease, is.na(diabetesd$heart_disease), Mode((diabetesd$heart_disease))),
imputed_modesh = replace(diabetesd$smoking_history, is.na(diabetesd$smoking_history), Mode(diabetesd$smoking_history)))
summary(value_imputed)
original original2 imputed_modehd imputed_modesh
Min. :0.00000 Length:100000 Min. :0.00000 Length:100000
1st Qu.:0.00000 Class :character 1st Qu.:0.00000 Class :character
Median :0.00000 Mode :character Median :0.00000 Mode :character
Mean :0.03943 Mean :0.03942
3rd Qu.:0.00000 3rd Qu.:0.00000
Max. :1.00000 Max. :1.00000
NA's :15
#plot the comparison of original data and mode imputed data
h1 <- ggplot(value_imputed, aes(x = original)) +
geom_histogram(bins=10, fill = "#ad1538", color = "#000000", position = "identity") +
ggtitle("Original for Heart Disease") +
theme_classic()
h2 <- ggplot(value_imputed, aes(x = original2)) +
geom_bar( fill = "#15ad4f", color = "#000000", position = "identity") +
ggtitle("Original for Smoking History") +
theme_classic()
h3 <- ggplot(value_imputed, aes(x = imputed_modehd)) +
geom_histogram(bins=10, fill = "#1543ad", color = "#000000", position = "identity") +
ggtitle("Mode-imputed for Heart Disease") +
theme_classic()
h4 <- ggplot(value_imputed, aes(x = imputed_modesh)) +
geom_bar( fill = "#ad8415", color = "#000000", position = "identity") +
ggtitle("Mode-imputed for Smoking History") +
theme_classic()
plot_grid(h1, h2, h3, h4, nrow = 2, ncol = 2)
Regression-Based Imputation for Numerical Variables
Using regression models, we can estimate missing values. For the
variable, bmi, we can predict the missing values using estimates from
our model. Bmi is a continuous variable, unlike the previous example
where our values could only be 0 or 1. In this method, a linear model
was created to help create estimates of our values.
#create a dataset for regression impute
regimpute<-diabetesd
# Identify rows where BMI is missing
missing_rows <- which(is.na(diabetesd$bmi)) # Get row indices
# Train a linear model using complete cases
lm_model <- lm(bmi ~ age + blood_glucose_level + HbA1c_level + heart_disease + hypertension + diabetes,
data = regimpute, na.action = na.exclude)
# Impute missing BMI values using the model
diabetesd$bmi[missing_rows] <- predict(lm_model, newdata = regimpute[missing_rows, ])
dep.mi <- bind_rows(
data.frame(value = diabetesd$bmi, imputed = regimpute$bmi))
#imp = "dep.imp1")
i7<-boxplot(diabetesd$bmi,
main = "Mean bmi in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
i8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
MICE Imputation
MICE is multiple imputation techniques used to impute missing values.
This method also uses regression models and accounts for uncertainty by
generating multiple possible values. Using MICE, the variables smoking
history, heart disease, and bmi, can be imputated within one function.
MICE can handle different types of variables, imputates based on the
relationship between variables and it accounts for variability in
missing data.
#reload dataset so that it is free of mode and regression imputation done previously
data2 <- read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/diabetes_prediction_dataset.csv')
#create missing values and make smoking history a binary variable
ltr.missing.id <- sample(1:1000, 50, replace = FALSE)
gpa.missing.id <- sample(1:1000, 15, replace = FALSE)
data2$smoking_history[data2$smoking_history== "No Info"] <-NA
data2$bmi[ltr.missing.id] <- NA
data2$heart_disease[gpa.missing.id] <- NA
#make variables numeric
data2$gender <- as.numeric(as.factor(data2$gender))
data2$heart_disease<- as.factor(as.numeric(data2$heart_disease))
data2$smoking_history<-as.factor(data2$smoking_history)
#apply MICE imputation
df_mice <- mice(data2, method = c("","","","pmm","polyreg","pmm","","",""), m = 20, maxit=20,seed = 123, print=F)
# Complete dataset with imputed values
df_imputed <- complete(df_mice)
#plot comparisons of before and after MICE imputation for heart disease
g1 <- ggplot(value_imputed, aes(x = imputed_modehd)) +
geom_bar(fill = "#1543ad", color = "#000000", position = "identity") +
ggtitle("Mode-imputed") +
labs(x="Heart Disease")+
theme_classic()
g2 <- ggplot(value_imputed, aes(x = original)) +
geom_bar(fill = "#ad1538", color = "#000000", position = "identity") +
ggtitle("Original") +
labs(x="Heart Disease")+
theme_classic()
g3 <- ggplot(df_imputed, aes(x = heart_disease)) +
geom_bar(fill = "purple", color = "#000000", position = "identity") +
ggtitle("MICE") +
labs(x="Heart Disease")+
theme_classic()
plot_grid(g1, g2, g3, nrow=1, ncol =3)
#plot comparisons for smoking history
g4 <- ggplot(df_imputed, aes(x = smoking_history)) +
geom_bar( fill = "purple", color = "#000000", position = "identity") +
ggtitle("MICE") +
labs(x="Smoking History")+
theme_classic()
g5 <- ggplot(value_imputed, aes(x = original2)) +
geom_bar( fill = "red", color = "#000000", position = "identity") +
ggtitle("Original Smoking History") +
labs(x="Smoking History")+
theme_classic()
g6 <- ggplot(value_imputed, aes(x = imputed_modesh)) +
geom_bar( fill = "blue", color = "#000000", position = "identity") +
ggtitle("Mode-imputed") +
labs(x="Smoking History")+
theme_classic()
plot_grid(g4,g5,g6, nrow=3, ncol=1)
#plot comparisons for bmi
g7<-boxplot(diabetesd$bmi,
main = "Mean bmi in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
g8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
g9 <-boxplot(df_imputed$bmi,
main = "MICE for BMI",
xlab = "BMI",
col = "purple",
border = "black",
horizontal = TRUE,
notch = TRUE
)
model5 <- with(df_mice, lm(diabetes ~ bmi+ heart_disease+ smoking_history ))
summary(pool(model5))
term estimate std.error statistic df
1 (Intercept) -1.588938e-01 0.0042264348 -37.59524385 8765.6364
2 bmi 8.387455e-03 0.0001291007 64.96833640 95903.5486
3 heart_disease1 2.213973e-01 0.0044025602 50.28829659 97099.1099
4 smoking_historyever 4.374612e-03 0.0044673218 0.97924717 768.3395
5 smoking_historyformer 3.923135e-02 0.0034242201 11.45701814 1528.3749
6 smoking_historynever -3.066871e-05 0.0026838513 -0.01142713 847.0962
7 smoking_historynot current 6.032198e-03 0.0038465169 1.56822334 577.2461
p.value
1 6.484235e-287
2 0.000000e+00
3 0.000000e+00
4 3.277661e-01
5 3.251856e-29
6 9.908854e-01
7 1.173770e-01
Skewness
Skewness is a measure of symmetry within a distribution. The skewness
measurements below are of the variables age, bmi, HbA1c level, and blood
glucose level, respectively. When skewness is equal to 0, we can assume
the data is normally distributed. When skewness is greater than 0, our
data is positively skewed, while a value less than zero indicates
negatively skewed data. For the diabetes dataset, the variables bmi and
blood glucose level are 1 or about 1, which indicate a significant right
skew in the distribution.
age1<- skewness(df_imputed$age)
bmi1<-skewness(df_imputed$bmi)
HbA1c1<-skewness( df_imputed$HbA1c_level)
glucose1<-skewness(df_imputed$blood_glucose_level)
mytable<-data.frame(age1,bmi1,HbA1c1, glucose1)
kable(mytable, caption= "Skewness of Numeric Variables")
Skewness of Numeric Variables
| -0.0519782 |
1.041976 |
-0.0668528 |
0.8216426 |
Analyzing Data
The next step is to find which variables are significantly important
when trying to predict diabetes. By using feature selection, we are able
to predict possible best fit models for our variable, diabetes. For this
data, we will focus on logistic regression. The variables of interest,
diabetes, is a binary variable indicating linear regression would not
make an ideal model.
Random Forest First, we will look at the best model
selected by feature selection through random forest:
# Prepare the data
df_trans$diabetes <- as.factor(df_trans$diabetes)
# Set up RFE control with random forest
control <- rfeControl(functions = rfFuncs, method = "cv", number = 10)
# Apply RFE to identify top features
results <- rfe(
x = df_trans[, !colnames(df_trans) %in% "diabetes"],
y = df_trans$diabetes,
sizes = c(1:9),
rfeControl = control
)
# Print the selected features
models<-data.frame(predictors(results))
kable(models, caption="Random Forest Selected Model")
Random Forest Selected Model
| HbA1c_level |
| blood_glucose_level |
| bmi |
| heart_disease |
| age |
| hypertension |
| gender |
| smoking_history |
Stepwise Logistic Regression Next, let’s look and
stepwise logistic regression
#Stepwise Logistic Regression
# Fit a full logistic regression model with all predictors
full_model <- glm(diabetes ~ ., data = df_trans, family = binomial)
# Perform stepwise selection (default is backward elimination)
step_model1 <- step(full_model, direction = "both")
Start: AIC=23047.57
diabetes ~ gender + age + hypertension + heart_disease + smoking_history +
bmi + HbA1c_level + blood_glucose_level
Df Deviance AIC
- smoking_history 4 23029 23045
<none> 23024 23048
- gender 1 23078 23100
- heart_disease 1 23176 23198
- hypertension 1 23308 23330
- bmi 1 24361 24383
- age 1 25096 25118
- blood_glucose_level 1 30572 30594
- HbA1c_level 1 34856 34878
Step: AIC=23044.52
diabetes ~ gender + age + hypertension + heart_disease + bmi +
HbA1c_level + blood_glucose_level
Df Deviance AIC
<none> 23029 23045
+ smoking_history 4 23024 23048
- gender 1 23087 23101
- heart_disease 1 23184 23198
- hypertension 1 23314 23328
- bmi 1 24369 24383
- age 1 25193 25207
- blood_glucose_level 1 30582 30596
- HbA1c_level 1 34865 34879
summary(step_model1)
Call:
glm(formula = diabetes ~ gender + age + hypertension + heart_disease +
bmi + HbA1c_level + blood_glucose_level, family = binomial,
data = df_trans)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -9.99142 0.11057 -90.360 < 2e-16 ***
gender 0.27068 0.03536 7.654 1.94e-14 ***
age 1.03388 0.02428 42.583 < 2e-16 ***
hypertension 0.80228 0.04665 17.198 < 2e-16 ***
heart_disease1 0.76240 0.06014 12.677 < 2e-16 ***
bmi 10.23780 0.28095 36.439 < 2e-16 ***
HbA1c_level 2.49236 0.03769 66.122 < 2e-16 ***
blood_glucose_level 10.29954 0.14902 69.113 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 58163 on 99999 degrees of freedom
Residual deviance: 23029 on 99992 degrees of freedom
AIC: 23045
Number of Fisher Scoring iterations: 8
Both selection types selected the same model! However I will still go
through the steps of cross-validation as though I was comparing the two
models.
Cross-Validation
Let’s explore cross-validation to see which model is best fit. For
logistic regression, it is meaningful to look at accuracy and kappa.
#add classification
df_trans$diabetes<- factor(ifelse(df_trans$diabetes==1, "Yes","No"))
train_control <- trainControl(
method = "cv", # cross-validation
number = 10, # 10-fold
classProbs = TRUE # use if you're tracking AUC, Sensitivity, etc.
)
#run CV model
cv_model <- train(
diabetes ~ hypertension + gender +age + HbA1c_level + blood_glucose_level + heart_disease + bmi,
data=df_trans,
method = "glm",
family = "binomial",
trControl = train_control
)
print(cv_model)
Generalized Linear Model
1e+05 samples
7e+00 predictors
2e+00 classes: 'No', 'Yes'
No pre-processing
Resampling: Cross-Validated (10 fold)
Summary of sample sizes: 90000, 90000, 90000, 90000, 90000, 90000, ...
Resampling results:
Accuracy Kappa
0.95935 0.7015624
Accuracy shows the overall correctness of the model predictions and
kappa measures the levels of agreement between variables. Values closer
to 1 suggest higher accuracy and better agreement. This model suggests
high accuracy and high agreement based on the values.
ROC Curve and AOC Curve
Confusion Matrices ROC is also known as Receiver
Operating Characteristic Analysis. It is a technique using graphs that
evaluates the performance of a binary model. Before plotting the ROC
curve, it is necessary to calculate the true positive rate (TPR) and
false positive rate (FPR). Below, are confusion matrices that were used
to calculate those values.
#ROC and AUC
df_trans$diabetes <- as.factor(df_trans$diabetes)
# fit a logistic
model.logit <- glm(diabetes ~ age + gender+ bmi+hypertension + heart_disease + blood_glucose_level+ HbA1c_level , family = binomial, data = df_trans)
# predict probability of P(Y = "Yes")
probabilities <- round(as.vector(predict(model.logit, type = "response")),3)
#
thresholds <- c(0.0, 0.25, 0.5, 0.75, 1.0)
# Loop through thresholds and create confusion matrices
for (threshold in thresholds) {
cat("\nConfusion Matrix for Threshold =", threshold, "\n")
# Convert probabilities to predictions
# am: 1 = manual transmission, 0 = automatic transmission
predictions <- ifelse(probabilities > threshold, "Yes", "No")
all_levels <- union(levels(factor(df_trans$diabetes)), levels(factor(predictions)))
# Generate confusion matrix
cm <- confusionMatrix(factor(predictions, levels=all_levels), factor(df_trans$diabetes,levels=all_levels), positive = "Yes")
print(cm$table)
}
Confusion Matrix for Threshold = 0
Reference
Prediction No Yes
No 354 0
Yes 8146 91500
Confusion Matrix for Threshold = 0.25
Reference
Prediction No Yes
No 4216 146
Yes 4284 91354
Confusion Matrix for Threshold = 0.5
Reference
Prediction No Yes
No 5307 867
Yes 3193 90633
Confusion Matrix for Threshold = 0.75
Reference
Prediction No Yes
No 6322 3340
Yes 2178 88160
Confusion Matrix for Threshold = 1
Reference
Prediction No Yes
No 8500 91500
Yes 0 0
ROC Curve
#create ROC curve
TPR = c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0))
FPR = c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0))
plot(FPR, TPR, type = "b", main = "An Illustrative ROC Curve", col ="blue",
xlab="1 - Specifity (FPR)", ylab = "Sensitivity (TPR)")
# add a off-diagonal representing random guess algorithm in binary prediction
abline(0,1, lty = 2, col = "red")
# legend
legend("bottomright", c("Logistic Model", "Random Guess"),
col=c("blue", "red"), lty = 1:2, bty="n", cex = 0.9)
AUC (Area under the Curve) AUC quantifies the
performance of the ROC curve into a single value that ranges from 0 to
1. The plot below uses the Riemann Sum approximation to estimate the
area under the curve.
#AUC
TPR = round(c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0)),3)
FPR = round(c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0)),3)
TPR0 = TPR[7:1]
FPR0 = FPR[7:1]
#plot(FPR0, TPR0, type = "b")
datSenSpe = data.frame(TPR0, FPR0)
ggROC = ggplot(data = datSenSpe, aes(x = FPR0, y=TPR0)) +
geom_line(col = "steelblue") +
geom_point(col = "red") +
geom_segment(x = FPR0, y = 0, xend = FPR0, yend = TPR0, color = 4) +
geom_segment(x = 0, y = 0, xend = FPR0[7], yend = 0, color = 6) +
ggtitle("Approximating the AUC of Logistic Model") +
xlab("1-specificity (FPR)") +
ylab("Sensitivity (TPR)") +
annotate("text", x = 0.025, y = 0.125, label= "A") +
annotate("text", x = 0.105, y = 0.5, label = "B") +
annotate("text", x = 0.605, y = 0.5, label = "C") +
theme(plot.title = element_text(hjust = 0.5),
legend.position = c(0.8, 0.2),
plot.margin = unit(c(0.15, 0.15, 0.75, 0.15), "inches"),
axis.line = element_line(size = 2, colour = "navy", linetype=1))
# partition the region under the ROC into trapezoids
ggplotly(ggROC)
AUC Value
A<-(0.041*1)/2
B<- ((0.504-0.041)*1)
C<- ((1-0.504)*1)
AUC<- A+B+C
kable(AUC, caption= "Area under the Curve")
Area under the Curve
| 0.9795 |
Conclusion for Model Fit
Our best fit model is : \[
\text{ Diabetes} = 9.99 - 0.27\times \text{gender} - 1.03\times
\text{age} -0.8\times \text{hypertension} - 0.76\times \text{heart
disease} -10.24\times \text{bmi} - 2.49\times \text{HbA1c level} -
-10.3\times \text{blood glucose level}
\]
The best fit model was selected based on a variety of different
features. Both stepwise selection and random forest selected the model
as best fit. After running performance analyses on the model, the model
was shown to be of high performance. This means that the variables
chosen for the final model are significant for predicting diabetes. The
model chose not to select smoking history as significant predictor for
the response variable. A possible suggestion for this would be to reduce
the number of response values to a binary response. Such as, “Have you
ever smoked?” and have the response be “Yes” or “No”. This could help in
predicting the relationship between smoking and diabetes.
LS0tCnRpdGxlOiAiQXBwbGllZCBNYWNoaW5lIExlYXJuaW5nIGZvciBEYXRhIEFuYWx5c2lzIgphdXRob3I6ICJHYWJyaWVsbGEgS2hhbGlsIgpkYXRlOiAiMjAyNS0wMi0xOCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9Cmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogbmF2eTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogYm9sZDsKfQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAyMnB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9CgpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKPC9zdHlsZT4KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikKICAgbGlicmFyeShrbml0cikKfQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCmxpYnJhcnkodGlkeXZlcnNlKQp9CmlmICghcmVxdWlyZSgiR0dhbGx5IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKbGlicmFyeShHR2FsbHkpCn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFZJTSkgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoRGVzY1Rvb2xzKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWljZSkKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJlc2hhcGUyKSAgIyBGb3IgZGF0YSByZXNoYXBpbmcKbGlicmFyeShjYXJldCkKbGlicmFyeShwUk9DKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShmYXN0RHVtbWllcykKYGBgCiMgT3ZlcnZpZXcgb2YgRGF0YQoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBkYXRhc2V0IHdhcyB0byBoZWxwIGZpbmQgcHJlZGljdG9ycyBvZiBkaWFiZXRlcy4gVGhlIGdvYWwgaXMgdG8gaGVscCBtZWRpY2FsIHByb2Zlc3Npb25hbHMgaWRlbnRpZnkgcGF0aWVudHMgd2l0aCBwb3RlbnRpYWwgcmlzayBmYWN0b3JzIG9mIGRpYWJldGVzLlRoZSBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHBhdGllbnQgZGVtb2dyYXBoaWNzIHN1Y2ggYXMgYWdlIGFuZCBnZW5kZXIsIGFzIHdlbGwgYXMgbWVkaWNhbCBpbmZvcm1hdGlvbiBpbmNsdWRpbmcgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYW5kIGh5cGVydGVuc2lvbi4gVGhlIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGFzZXQgd2VyZSBvYnRhaW5lZCBmcm9tIHJlc2VhcmNoIHN0dWRpZXMgYW5kIGhlYWx0aGNhcmUgaW5zdGl0dXRpb25zLiBUaGUgZGF0YXNldCB3YXMgb2J0YWluZWQgdmlhIEthZ2dsZS4gCgpNdXN0YWZhLCBULiBaLiAoMjAyMSkuICpEaWFiZXRlcyBQcmVkaWN0aW9uIERhdGFzZXQqLiBLYWdnbGUuIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvaWFtbXVzdGFmYXR6L2RpYWJldGVzLXByZWRpY3Rpb24tZGF0YXNldAoKVGhlIGRhdGFzZXQgY29uc2lzdHMgb2YgOCBwcmVkaWN0b3IgdmFyaWFibGVzIGZvciBkaWFiZXRlczoKJ2dlbmRlcicgdGhlIHBhdGllbnQncyBnZW5kZXIgYXMgbWFsZSBvciBmZW1hbGUuCidhZ2UnIHRoZSBhZ2Ugb2YgdGhlIHBhdGllbnQgaW4geWVhcnMuCidoeXBlcnRlbnNpb24nIHllcyBvciBubywgb24gd2hldGhlciB0aGUgcGF0aWVudCBoYXMgaHlwZXJ0ZW5zaW9uLgonaGVhcnQgZGlzZWFzZScgeWVzIG9yIG5vLCBvbiB3aGV0aGVyIHRoZSBwYXRpZW50IGhhcyBoZWFydCBkaXNlYXNlLgonc21va2luZyBoaXN0b3J5JyB0aGUgcGF0aWVudCdzIHNtb2tpbmcgaGlzdG9yeSBpbmRpY2F0ZWQgYXMgbmV2ZXIsIG5vIGluZm8sIGN1cnJlbnQsIGZvcm1lciBvciBub3QgY3VycmVudC4KJ2JtaScgdGhlIHBhdGllbnQncyBib2R5IG1hc3MgaW5kZXggKGtnL20qKjIpLgonSGJBMWMgbGV2ZWwnIHRoZSBwYXRpZW50J3MgYXZlcmFnZSBibG9vZCBzdWdhciBsZXZlbCBvdmVyIHRoZSBwYXN0IDItMyBtb250aHMgKCUpLgonYmxvb2QgZ2x1Y29zZSBsZXZlbCcgYW1vdW50IG9mIGJsb29kIHN1Z2FyIGluIHRoZSBwYXRpZW50J3MgYmxvb2QgKG1nL2RMKS4KCgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBvZiBzaG93cyB0aGUgZnJlcXVlbmN5IG9mIHBhdGllbnRzIHdpdGggZGlhYmV0ZXMgYW5kIGh5cGVydGVuc2lvbi4gVGhlIHBsb3QgaW5kaWFjdGVzIGEgaGlnaGVyIGZyZXF1ZW5jeSBvZiBwYXRpZW50cyBub3QgaGF2aW5nIGRpYWJldGVzIGFuZCBub3QgaGF2aW5nIGh5cGVydGVuc2lvbi4gVGhlcmUgZG9lcyBub3Qgc2VlbSB0byBiZSBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIGhhdmluZyBkaWFiZXRlcyBhbmQgaGF2aW5nIGh5cGVydGVuc2lvbiBiYXNlZCBvbiB0aGUgbG93IGZyZXF1ZW5jeSBvZiBwYXRpZW50cyBoYXZpbmcgYm90aC4gJ30KI2xvYWQgaW4gZGF0YXNldApkYXRhIDwtcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HYWJieUs4L0RhdGFzZXRzL3JlZnMvaGVhZHMvbWFpbi9kaWFiZXRlc19wcmVkaWN0aW9uX2RhdGFzZXQuY3N2JykKZGlhYmV0ZXNkPC1kYXRhCgojY2hhbmdlIGhlYXJ0IGRpc2Vhc2UsIGRpYWJldGVzIGFuZCBoeXBlcnRlbnNpb24gdG8gMSBhbmQgMCBmb3IgZWFzaWVyIHVzZSBpbiBNSUNFLgpkYXRhJGRpYWJldGVzIDwtIHJlY29kZShkYXRhJGRpYWJldGVzLCAiMSI9IlllcyIsICIwIj0iTm8iKQpkYXRhJGh5cGVydGVuc2lvbiA8LSByZWNvZGUoZGF0YSRoeXBlcnRlbnNpb24sICIxIj0iWWVzIiwgIjAiPSJObyIpCmRhdGEkaGVhcnRfZGlzZWFzZSA8LSByZWNvZGUoZGF0YSRoZWFydF9kaXNlYXNlLCAiMSI9IlllcyIsICIwIj0iTm8iKQoKI3Bsb3QgaW50ZXJhY3Rpb24gYmV0d2VlbiBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uLgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBoeXBlcnRlbnNpb24sIGZpbGwgPSBkaWFiZXRlcykpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsgIyBVc2UgInN0YWNrIiBmb3IgYSBzdGFja2VkIGJhciBjaGFydAogIGxhYnMgKHRpdGxlPSJSaXNrIG9mIERpYWJldGVzIGJ5IEh5cGVydGVuc2lvbiIsIHg9Ikh5cGVydGVuc2lvbiIsIHk9ICJGcmVxdWVuY3kiLAogICAgICAgIGZpbGw9ICJEaWFiZXRlcyIpCgpgYGAKCiMgQ29tcGFyaXNvbiBvZiBUd28gQ2F0ZWdvcmljYWwgVmFyaWFibGVzCgpUaGUgcHVycG9zZSBvZiB0aGlzIGdyYXBoIGlzIHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhhdmluZyBoeXBlcnRlbnNpb24gYW5kIGRpYWJldGVzLiBGb3IgdGhpcyBncmFwaCwgSSBjaGFuZ2VkIHRoZSB2YWx1ZXMgb2YgMSBpbiBib3RoIHRoZSBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uIHZhcmlhYmxlIHRvICJZZXMiIGFuZCB0aGUgdmFsdWUgMCB0byAiTm8uIiBUaGVzZSBpbnRlZ2VycyB3ZXJlIG1lYW50IHRvIHJlcHJlc2VudCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgd2l0aCAxIGNvcnJlbGF0aW5nIHRvIGJlaW5nIHBvc2l0aXZlIGZvciBoeXBlcnRlbnNpb24gb3IgZGlhYmV0ZXMgYW5kIDAgY29ycmVsYXRpbmcgdG8gYmVpbmcgbmVnYXRpdmUgdG8gaHlwZXJ0ZW5zaW9uIG9yIGRpYWJldGVzLiBCYXNlZCBvbiBvdXIgZ3JhcGgsIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGhhdmluZyBkaWFiZXRlcyBhbmQgaGF2aW5nIGh5cGVydGVuc2lvbiwgd2l0aCBtb3N0IHBhdGllbnRzIHdpdGhpbiBvdXIgc2FtcGxlIGhhdmluZyBuZWl0aGVyIGRpYWJldGVzIG9yIGh5cGVydGVuc2lvbi4gVGh1cywgaHlwZXJ0ZW5zaW9uIHdvdWxkIG5vdCBiZSBhIGdvb2QgcHJlZGljdG9yIG9mIGRpYWJldGVzIHdpdGhpbiBwYXRpZW50cy4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBzaG93cyB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiBibG9vZCBnbHVjb3NlIGxldmVscyBhbmQgSGJBMWMgbGV2ZWxzIG9uIGRpYWJldGVzLiBCYXNlZCBvbiB0aGUgcGxvdCwgaGlnaGVyIGJsb29kIGdsdWNvc2UgbGV2ZWxzIGFuZCBIYkExYyBsZXZlbHMgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHRoZSBwcmVzZW5jZSBvZiBkaWFiZXRlcy4gSW4gY29tcGFyaXNvbiwgbG93ZXIgbGV2ZWxzLCBpbmRpY2F0ZSB0aGF0IGEgcGF0aWVudCB3aWxsIG1vcmUgY29tbW9ubHkgbm90IGhhdmUgZGlhYmV0ZXMuIFRoZSBoZWlnaHQgb2YgdGhlIHBvaW50cyBzaG93biBmb3IgZGlhYmV0ZXMgcmVwcmVzZW50IHRoZSBsZXZlbHMgb2YgSGJBMWMsIGJhc2VkIG9uIHRoZSBwbG90LCBIYkExYyBsZXZlbHMgcHJlZGljdCB0aGUgcHJlc2VuY2Ugb2YgZGlhYmV0ZXMgbW9yZSBvZnRlbiB0aGFuIGJsb29kIGdsdWNvc2UgbGV2ZWxzLiAnfQoKCmludGVyYWN0ID0gZ2dwbG90KGRhdGEsIGFlcyh4ID1ibG9vZF9nbHVjb3NlX2xldmVsICwgeSA9IEhiQTFjX2xldmVsLCBncm91cCA9IGRpYWJldGVzLCBjb2xvciA9IGRpYWJldGVzKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKyAgIyBMaW5lcyByZXByZXNlbnRpbmcgaW50ZXJhY3Rpb24KICBnZW9tX3BvaW50KHNpemUgPSAyKSArICMgUG9pbnRzIGZvciBkYXRhCiAgbGFicygKICAgIHRpdGxlID0gIkludGVyYWN0aW9uIG9mIEJsb29kIEdsdWNvc2UgYW5kIEhiQTFjIExldmVscyIsCiAgICB4ID0gIkJsb29kIEdsdWNvc2UgTGV2ZWwiLAogICAgeSA9ICJIYkExYyBMZXZlbCIsCiAgICBjb2xvciA9ICJQcmVzZW5jZSBvZiBEaWFiZXRlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIKICApCmludGVyYWN0CgpgYGAKIyBDb21wYXJpc29uIG9mIFR3byBOdW1lcmljYWwgVmFyaWFibGVzCgpUaGUgdHdvIHZhcmlhYmxlcyBiZWluZyBjb21wYXJlZCBoZXJlIGFyZSBCbG9vZCBHbHVjb3NlIExldmVsIGFuZCBIYkExYyBMZXZlbC4gSGJBMWNjIGlzIGEgc2hvcnRlbmVkIHRlcm0gZm9yIGhlbW9nbG9iaW4gQTFjLiBIYjFBYyBsZXZlbCBpcyBhIG1lYXN1cmUgb2YgYXZlcmFnZSBibG9vZCBzdWdhciBsZXZlbHMgb3ZlciAyLTMgbW9udGhzIGFuZCBpcyBtZWFzdXJlZCBpbiAlLiBCbG9vZCBnbHVjb3NlIGxldmVsIGlzIHRoZSBhbW91bnQgb2YgYmxvb2Qgc3VnYXIgaW4gYSBwYXRpZW50cyBibG9vZCBhdCBhIGdpdmVuIHRpbWUuIE91ciBwbG90IHNob3dzIGEgY29ycmVsYXRpb24gYmV0d2VlbiBoaWdoIGxldmVscyBpbiBIYkExYyBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYW5kIGl0J3MgcmVsYXRpb25zaGlwIHdpdGggZGlhYmV0ZXMuIFRoaXMgcGxvdCBzdWdnZXN0cyBwYXRpZW50cyB3aXRoIGhpZ2ggbGV2ZWxzIG9mIEhiQTFjIGFuZCBibG9vZCBnbHVjb3NlIGxldmVscyBhcmUgYXQgaGlnaCByaXNrIGZvciBkaWFiZXRlcy4KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJveHBsb3Qgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBhbmQgcHJlc2VuY2Ugb2YgZGlhYmV0ZXMuIFRoZSBib3hwbG90IHNob3dzIHRoYXQgb2xkZXIgcGF0aWVudHMgb24gYXZlcmFnZSBhcmUgbW9yZSBvZnRlbiBoYXZlIGRpYWJldGVzLiBUaGVyZSBhcmUgYSBmZXcgb3V0bGllcnMgaW4gdGhlIGRpYWJldGVzIHBvcHVsYXRpb24gdGhhdCBhcHBlYXIgdG8gYmUgdW5kZXIgdGhlIGFnZSBvZiAyMCB5ZWFycy4gVGhpcyBjb3VsZCBiZSByZXByZXNlbnRhdGl2ZSBvZiBwYXRpZW50cyB3aXRoIFR5cGUgSSBkaWFiZXRlcywgc2luY2UgdGhlIGRhdGEgZG9lcyBub3QgZGlzdGluZ3Vpc2ggYmV0d2VlbiBUeXBlIEkgYW5kIFR5cGUgSUkgZGlhYmV0ZXMuICd9CgojcGxvdCBvZiBhIG51bWVyaWNhbCBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGUKIGJveHBsb3QoZGF0YSRhZ2UgfiBkYXRhJGRpYWJldGVzLAogICAgICAgICB4bGFiPSJQYXRpZW50IEFnZSIsCiAgICAgICAgIHlsYWI9IlByZXNlbmNlIG9mIERpYWJldGVzIiwKICAgICAgICAgY29sID0gYygic2t5Ymx1ZSIsICJwdXJwbGUiKSwKICAgICAgICAgbWFpbj0iVmlzdWFsaXphdGlvbiBvZiBEaWFiZXRlcyBieSBBZ2UiLAogICAgICAgICBjZXgubWFpbiA9IDEuMSwKICAgICAgICAgY29sLm1haW4gPSAibmF2eSIpCmBgYAoKIyBDb21wYXJpc29uIG9mIGEgTnVtZXJpY2FsIGFuZCBDYXRlZ29yaWNhbCBWYXJpYWJsZXMKClRoaXMgY2hhcnQgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBhbmQgZGlhYmV0ZXMgZGlhZ25vc2lzLiBUaGlzIGNoYXJ0IHNob3dzIHRoYXQgYXMgcGF0aWVudHMgZ3JvdyBvbGRlciB0aGV5IGFyZSBhdCBoaWdoZXIgcmlzayBmb3IgZGlhYmV0ZXMuIFRoaXMgd291bGQgbWFrZSBhZ2UgYSBwcmVkaWN0b3IgZm9yIGRpYWJldGVzLCB3aXRoIHRoZSBhdmVyYWdlIGFnZSBmb3IgdGhvc2Ugd2l0aG91dCBkaWFiZXRlcyBiZWluZyA0MCB5ZWFycyBhbmQgNjAgeWVhcnMgZm9yIHRob3NlIHdpdGggZGlhYmV0ZXMuIEhvd2V2ZXIsIHdlIGNhbiBzZWUgdGhhdCB3ZSBkbyBoYXZlIGEgZmV3IG91dGxpZXJzIGZvciB0aG9zZSB3aXRoIGRpYWJldGVzIHdpdGggc29tZSBwYXRpZW50cyBiZWluZyBkaWFnbm9zZWQgYXQgMjAgb3IgeW91bmdlci4gVGhpcyBjb3VsZCBiZSBmcm9tIHRoZSBwb3B1bGF0aW9uIG9mIHBlb3BsZSB3aXRoIFR5cGUgSSBkaWFiZXRlcyB3aGljaCBpcyB1c3VhbGx5IGRpYWdub3NlZCBpbiBwYXRpZW50cyB1bmRlciAyMC4gT3VyIGRhdGFzZXQgZG9lcyBub3QgZGlzdGluZ3Vpc2ggYmV0d2VlbiB0eXBlIEkgYW5kIHR5cGUgSUkgZGlhYmV0ZXMuCgoKIyBDb25jbHVzaW9uIGZvciBDb21wYXJpc29uIG9mIFZhcmlhYmxlcwoKRGlhYmV0ZXMgY2FuIGJlIHByZWRpY3RlZCB1c2luZyBhZ2UsIGJsb29kIGdsdWNvc2UgbGV2ZWxzLCBhbmQgSGJBMWMgbGV2ZWxzIGluIHBhdGllbnRzLiBIb3dldmVyLCBvdXIgcmVzdWx0cyBzaG93ZWQgaHlwZXJ0ZW5zaW9uIGlzIG5vdCBhIGdvb2QgcHJlZGljdG9yIG9mIGRpYWJldGVzLiBCYXNlZCBvbiBvdXIgZmluZGluZ3MsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGxvb2sgYXQgZmFjdG9ycyB0aGF0IG9jY3VyIG9uY2UgYSBwYXRpZW50IGJlY29tZXMgb2xkZXIgdGhhdCBjb3VsZCBsZWFkIHRvIGRpYWJldGVzIGF0IGFuIG9sZGVyIGFnZS4gQXMgd2VsbCwgZGlldCBjb3VsZCBiZSBhbm90aGVyIGZhY3RvciB0byBsb29rIGludG8sIHN1Y2ggYXMgZ3JhbXMgb2Ygc3VnYXIgY29uc3VtZWQgb24gYSBkYWlseSBvciB3ZWVrbHkgYmFzaXMsIHRvIHNlZSBpZiBzdWdhciBjb25zdW1wdGlvbiBjYW4gcHJlZGljdCBkaWFiZXRlcy4gQW5vdGhlciBpbXBvcnRhbnQgdGhpbmcgdG8gYW5hbHl6ZSBpbiBmdXR1cmUgc3R1ZGllcyB3b3VsZCBiZSBUeXBlIEkgdmVyc3VzIFR5cGUgSUkgZGlhYmV0ZXMsIGFzIGl0IGNvdWxkIGJlIHRoZSByZWFzb24gZm9yIHNvbWUgb2YgdGhlIG91dGxpZXJzIGluIHRoZSBib3hwbG90LiAKCgojIyBPdmVydmlldyBvZiBNaXNzaW5nIFZhcmlhYmxlcwoKQW4gaW1wb3J0YW50IHN0ZXAgaW4gZGF0YSBhbmFseXNpcyBmb3IgbWFjaGluZSBsZWFybmluZyBpcyBoYW5kbGluZyBtaXNzaW5nIHZhbHVlcy4gTWlzc2luZyB2YWx1ZXMgaW4gYSBkYXRhc2V0IGNhbiBvY2N1ciBmb3IgbWFueSByZWFzb25zLCBidXQgbm90IGxpbWl0ZWQgdG8gbm9uLXJlc3BvbnNlIGluIHN1cnZleXMsIHBhcnRpY2lwYW50cyBsZWF2aW5nIHRoZSBzdHVkeSwgZGF0YSBlbnRyeSBlcnJvcnMgYW5kIHN5c3RlbSBsaW1pdGF0aW9ucy4gSWYgbWlzc2luZyB2YWx1ZXMgYXJlIG5vdCBhZGRyZXNzZWQsIG1vZGVscyBjYW4gYmVjb21lIGJpYXNlZCBhbmQgYWNjdXJhY3kgb2YgdGhlIGFuYXlseXNpcyBjYW4gZGVjcmVhc2UuIFRoaXMgc2VjdGlvbiBleGFtaW5lcyBkaWZmZXJlbnQgaW1wdXRhdGlvbiBzdHJhdGVnaWVzIHRvIGVmZmVjdGl2ZWx5IGhhbmRsZSBtaXNzaW5nIHZhbHVlcy4KClRoZSBpbXB1dGF0aW9uIG1ldGhvZHMgd2Ugd2lsbCBleGFtaW5lIGluY2x1ZGU6CgpSZXBsYWNlbWVudCBJbXB1dGF0aW9uIGZvciBDYXRlZ29yaWNhbCBGZWF0dXJlczogTW9kZSBpbXB1dGF0aW9uIGFuZCBLTk4tYmFzZWQgaW1wdXRhdGlvbi4KClJlZ3Jlc3Npb24tYmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIEZlYXR1cmVzOiBQcmVkaWN0aXZlIG1vZGVsaW5nIHRvIGVzdGltYXRlIG1pc3NpbmcgdmFsdWVzLgoKTXVsdGlwbGUgSW1wdXRhdGlvbjogQWR2YW5jZWQgbWV0aG9kcyBzdWNoIGFzIE1JQ0UgdG8gaW1wcm92ZSByb2J1c3RuZXNzLgoKYGBge3J9CiMgY3JlYXRlIHJhbmRvbSBvYnNlcnZhdGlvbiBJRCBhbmQgcmVwbGFjZSB0aGUgY29ycmVzcG9uZGluZyBvYnMgd2l0aCBtaXNzaW5nCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkaWFiZXRlc2QkYm1pW2x0ci5taXNzaW5nLmlkXSA8LSBOQQpkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeVtkaWFiZXRlc2Qkc21va2luZ19oaXN0b3J5ID09ICJObyBJbmZvIl0gPC0gTkEKCmBgYAoKIyBNb2RlIEltcHV0YXRpb24gZm9yIENhdGVnb3JpY2FsIFZhcmlhYmxlcwoKSW4gdGhpcyBtZXRob2QsIG1pc3NpbmcgdmFyaWFibGVzIGFyZSByZXBsYWNlZCB3aXRoIHRoZSBtb3N0IGZyZXF1ZW50IGNhdGVnb3J5IG9mIHRoZSBjb3JyZXNwb25kaW5nIHZhcmlhYmxlLiBNb2RlIGltcHV0YXRpb24gZW5zdXJlcyBjb25zaXN0ZW5jeSBhbmQgd29ya3Mgd2VsbCB3aGVuIG1pc3NpbmcgdmFsdWVzIGFyZSByYW5kb21seSBkaXN0cmlidXRlZC4gQmVsb3csIG1vZGUgaW1wdXRhdGlvbiBpcyB1c2VkIG9uIHRoZSB2YXJpYWJsZSwgaGVhcnQgZGlzZWFzZSwgd2hpY2ggaXMgMSBpZiB0aGUgcGF0aWVudCBoYXMgaGVhcnQgZGlzZWFzZSBhbmQgMCBpZiB0aGUgcGF0aWVudCBkb2VzIG5vdCBoYXZlIGhlYXJ0IGRpc2Vhc2UuVGhlIHZhcmlhYmxlIHNtb2tpbmcgaGlzdG9yeSBoYWQgY3VycmVudCwgZm9ybWVyLCBubyBpbmZvLCBuZXZlciwgYW5kIGV2ZXIgYXMgcG9zc2libGUgdmFsdWVzLiBObyBJbmZvIGluZGljYXRlcyB0aGF0IHdlIGRvIG5vdCBoYXZlIGluZm9ybWF0aW9uIG9uIHRoZSBwYXJ0aWNpcGFudCdzIHNtb2tpbmcgaGlzdG9yeSBhbmQgd2lsbCBiZSB0cmVhdGVkIGFzIGEgbWlzc2luZyB2YWx1ZXMuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBwbG90IHNob3dzIHRoZSBjb21wYXJpc29uIGJldHdlZW4gdGhlIG9yaWdpbmFsIGRhdGEgY29udGFpbmluZyBtaXNzaW5nIHZhbHVlcyBmb3IgdGhlIHZhcmlhYmxlcyBoZWFydCBkaXNlYXNlIGFuZCBzbW9raW5nIGhpc3RvcnksIGFuZCB0aGUgZGF0YSBhZnRlciB1c2luZyBtb2RlIGltcHV0ZS4gVGhlIGhpc3RvZ3JhbXMgc2hvdyB0aGF0IG1vZGUgaW1wdXRlIHVzZWQgd2hhdCB3YXMgbW9zdCBjb21tb24gdG8gcmVwbGFjZSB0aGUgbWlzc2luZyB2YWx1ZXMuIFRoaXMgaXMgc2VlbiBjbGVhcmx5IGluIHRoZSB2YXJpYWJsZSBzbW9raW5nIGhpc3RvcnksIHdoZXJlICJuZXZlciIgd2VudCBmcm9tIG9yaWdpbmFsbHkgYSBjb3VudCBvZiBhYm91dCA0MCwwMDAgdG8gYWJvdXQgNzAsMDAwLiBIZWFydCBkaXNlYXNlIGhhZCBhIHNtYWxsIGFtb3VudCBvZiBtaXNzaW5nIGRhdGEgKG9ubHkgMTUpLCBob3dldmVyIHRoZSAxNSBtaXNzaW5nIHdlcmUgY2hhbmdlZCB0byAwLCBpbmRpY2F0aW5nIHRoZSBwYXRpZW50IHdvdWxkIG5vdCBoYXZlIGhlYXJ0IGRpc2Vhc2UuJ30KCgpkaWFiZXRlc2QgPC1kaWFiZXRlc2QKIyBGdW5jdGlvbiB0byBpbXB1dGUgbW9kZQoKTW9kZSA8LSBmdW5jdGlvbih4KSB7CiAgdXggPC0gdW5pcXVlKG5hLm9taXQoeCkpICAjIFJlbW92ZSBOQXMgYmVmb3JlIGNvbXB1dGluZyBtb2RlCiAgdGFiIDwtIHRhYnVsYXRlKG1hdGNoKHgsIHV4KSkKICBtb2RlX3ZhbHVlIDwtIHV4W3doaWNoLm1heCh0YWIpXQogIAogICMgRW5zdXJlIG1vZGVfdmFsdWUgaXMgb2YgdGhlIHNhbWUgdHlwZSBhcyB4CiAgaWYgKGlzLmZhY3Rvcih4KSkgewogICAgcmV0dXJuKGZhY3Rvcihtb2RlX3ZhbHVlLCBsZXZlbHMgPSBsZXZlbHMoeCkpKQogIH0gZWxzZSBpZiAoaXMuY2hhcmFjdGVyKHgpKSB7CiAgICByZXR1cm4oYXMuY2hhcmFjdGVyKG1vZGVfdmFsdWUpKQogIH0gZWxzZSB7CiAgICByZXR1cm4oYXMubnVtZXJpYyhtb2RlX3ZhbHVlKSkKICB9Cn0KI2FwcGx5IG1vZGUgaW1wdXRhdGlvbgp2YWx1ZV9pbXB1dGVkIDwtIGRhdGEuZnJhbWUoCiAgb3JpZ2luYWwgPSBkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZSwKICBvcmlnaW5hbDI9ZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeSwKICBpbXB1dGVkX21vZGVoZCA9IHJlcGxhY2UoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UsIGlzLm5hKGRpYWJldGVzZCRoZWFydF9kaXNlYXNlKSwgTW9kZSgoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UpKSksCiAgaW1wdXRlZF9tb2Rlc2ggPSByZXBsYWNlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnksIGlzLm5hKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpLCBNb2RlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpKSkKc3VtbWFyeSh2YWx1ZV9pbXB1dGVkKQoKI3Bsb3QgdGhlIGNvbXBhcmlzb24gb2Ygb3JpZ2luYWwgZGF0YSBhbmQgbW9kZSBpbXB1dGVkIGRhdGEKaDEgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gb3JpZ2luYWwpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0xMCwgZmlsbCA9ICIjYWQxNTM4IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk9yaWdpbmFsIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMiA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBvcmlnaW5hbDIpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAiIzE1YWQ0ZiIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMyA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVoZCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTEwLCBmaWxsID0gIiMxNTQzYWQiLCBjb2xvciA9ICIjMDAwMDAwIiwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiTW9kZS1pbXB1dGVkIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoNCA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVzaCkpICsKICBnZW9tX2JhciggZmlsbCA9ICIjYWQ4NDE1IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1vZGUtaW1wdXRlZCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQoKCnBsb3RfZ3JpZChoMSwgaDIsIGgzLCBoNCwgbnJvdyA9IDIsIG5jb2wgPSAyKQoKCgpgYGAKIyBSZWdyZXNzaW9uLUJhc2VkIEltcHV0YXRpb24gZm9yIE51bWVyaWNhbCBWYXJpYWJsZXMKClVzaW5nIHJlZ3Jlc3Npb24gbW9kZWxzLCB3ZSBjYW4gZXN0aW1hdGUgbWlzc2luZyB2YWx1ZXMuIEZvciB0aGUgdmFyaWFibGUsIGJtaSwgd2UgY2FuIHByZWRpY3QgdGhlIG1pc3NpbmcgdmFsdWVzIHVzaW5nIGVzdGltYXRlcyBmcm9tIG91ciBtb2RlbC4gQm1pIGlzIGEgY29udGludW91cyB2YXJpYWJsZSwgdW5saWtlIHRoZSBwcmV2aW91cyBleGFtcGxlIHdoZXJlIG91ciB2YWx1ZXMgY291bGQgb25seSBiZSAwIG9yIDEuIEluIHRoaXMgbWV0aG9kLCBhIGxpbmVhciBtb2RlbCB3YXMgY3JlYXRlZCB0byBoZWxwIGNyZWF0ZSBlc3RpbWF0ZXMgb2Ygb3VyIHZhbHVlcy4gCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBib3hwbG90cyBzaG93IHRoZSBjb21wYXJpc29uIG9mIHRoZSB2YXJpYWJsZSBibWkgYmVmb3JlIGFuZCBhZnRlciByZWdyZXNzaW9uIGltcHV0YXRpb24uJyB9CgojY3JlYXRlIGEgZGF0YXNldCBmb3IgcmVncmVzc2lvbiBpbXB1dGUKcmVnaW1wdXRlPC1kaWFiZXRlc2QKCiMgSWRlbnRpZnkgcm93cyB3aGVyZSBCTUkgaXMgbWlzc2luZwptaXNzaW5nX3Jvd3MgPC0gd2hpY2goaXMubmEoZGlhYmV0ZXNkJGJtaSkpICAjIEdldCByb3cgaW5kaWNlcwoKCiMgVHJhaW4gYSBsaW5lYXIgbW9kZWwgdXNpbmcgY29tcGxldGUgY2FzZXMKbG1fbW9kZWwgPC0gbG0oYm1pIH4gYWdlICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIEhiQTFjX2xldmVsICsgaGVhcnRfZGlzZWFzZSArIGh5cGVydGVuc2lvbiArIGRpYWJldGVzLCAKICAgICAgICAgICAgICAgZGF0YSA9IHJlZ2ltcHV0ZSwgbmEuYWN0aW9uID0gbmEuZXhjbHVkZSkKCiMgSW1wdXRlIG1pc3NpbmcgQk1JIHZhbHVlcyB1c2luZyB0aGUgbW9kZWwKZGlhYmV0ZXNkJGJtaVttaXNzaW5nX3Jvd3NdIDwtIHByZWRpY3QobG1fbW9kZWwsIG5ld2RhdGEgPSByZWdpbXB1dGVbbWlzc2luZ19yb3dzLCBdKQoKCmRlcC5taSA8LSBiaW5kX3Jvd3MoCiAgZGF0YS5mcmFtZSh2YWx1ZSA9IGRpYWJldGVzZCRibWksIGltcHV0ZWQgPSByZWdpbXB1dGUkYm1pKSkKICAgICAgICAgICAgICNpbXAgPSAiZGVwLmltcDEiKQoKCmk3PC1ib3hwbG90KGRpYWJldGVzZCRibWksCm1haW4gPSAiTWVhbiBibWkgaW4gT3JpZ2luYWwgRGF0YSIsCnhsYWIgPSAiQk1JIiwKY29sID0gImJsdWUiLApib3JkZXIgPSAiYmxhY2siLApob3Jpem9udGFsID0gVFJVRSwKbm90Y2ggPSBUUlVFCikKaTggPC1ib3hwbG90KHJlZ2ltcHV0ZSRibWksCm1haW4gPSAiUmVncmVzc2lvbiBJbXB1dGF0aW9uIGZvciBCTUkiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJyZWQiLApib3JkZXIgPSAiYmxhY2siLApob3Jpem9udGFsID0gVFJVRSwKbm90Y2ggPSBUUlVFCikKCgogCgpgYGAKCiMgTUlDRSBJbXB1dGF0aW9uCgpNSUNFIGlzIG11bHRpcGxlIGltcHV0YXRpb24gdGVjaG5pcXVlcyB1c2VkIHRvIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4gVGhpcyBtZXRob2QgYWxzbyB1c2VzIHJlZ3Jlc3Npb24gbW9kZWxzIGFuZCBhY2NvdW50cyBmb3IgdW5jZXJ0YWludHkgYnkgZ2VuZXJhdGluZyBtdWx0aXBsZSBwb3NzaWJsZSB2YWx1ZXMuIFVzaW5nIE1JQ0UsIHRoZSB2YXJpYWJsZXMgc21va2luZyBoaXN0b3J5LCBoZWFydCBkaXNlYXNlLCBhbmQgYm1pLCBjYW4gYmUgaW1wdXRhdGVkIHdpdGhpbiBvbmUgZnVuY3Rpb24uIE1JQ0UgY2FuIGhhbmRsZSBkaWZmZXJlbnQgdHlwZXMgb2YgdmFyaWFibGVzLCBpbXB1dGF0ZXMgYmFzZWQgb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcyBhbmQgaXQgYWNjb3VudHMgZm9yIHZhcmlhYmlsaXR5IGluIG1pc3NpbmcgZGF0YS4gCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nQmFzZWQgb24gdGhlIHRocmVlIGdyYXBocywgTUlDRSBzZWVtcyB0byBoYXZlIHByb2R1Y2VkIHZhbHVlcyB0aGF0IGFwcGVhciBhbG1vc3QgaWRlbnRpY2FsIHRvIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiBNb2RlIGltcHV0ZSBzZWVtcyB0byBiZSBzbGlnaHRseSBkaWZmZXJlbnQgc2luY2UgaXQgcmVsaWVzIG9uIGZpbGxpbmcgbWlzc2luZyB2YWx1ZXMgd2l0aCB0aGUgbW9zdCBjb21tb24gdmFsdWUuIEluIHRoaXMgY2FzZSwgbW9kZSBpbXB1dGUgZmlsbGVkIGFsbCBtaXNzaW5nIHZhbHVlcyBhcyAwIGFuZCB1bmRlci1yZXByZXNlbnRlZCAxLid9CgojcmVsb2FkIGRhdGFzZXQgc28gdGhhdCBpdCBpcyBmcmVlIG9mIG1vZGUgYW5kIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbiBkb25lIHByZXZpb3VzbHkKZGF0YTIgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HYWJieUs4L0RhdGFzZXRzL3JlZnMvaGVhZHMvbWFpbi9kaWFiZXRlc19wcmVkaWN0aW9uX2RhdGFzZXQuY3N2JykKCiNjcmVhdGUgbWlzc2luZyB2YWx1ZXMgYW5kIG1ha2Ugc21va2luZyBoaXN0b3J5IGEgYmluYXJ5IHZhcmlhYmxlCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkYXRhMiRzbW9raW5nX2hpc3RvcnlbZGF0YTIkc21va2luZ19oaXN0b3J5PT0gIk5vIEluZm8iXSA8LU5BCmRhdGEyJGJtaVtsdHIubWlzc2luZy5pZF0gPC0gTkEKZGF0YTIkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKCiNtYWtlIHZhcmlhYmxlcyBudW1lcmljCmRhdGEyJGdlbmRlciA8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkYXRhMiRnZW5kZXIpKQpkYXRhMiRoZWFydF9kaXNlYXNlPC0gYXMuZmFjdG9yKGFzLm51bWVyaWMoZGF0YTIkaGVhcnRfZGlzZWFzZSkpCmRhdGEyJHNtb2tpbmdfaGlzdG9yeTwtYXMuZmFjdG9yKGRhdGEyJHNtb2tpbmdfaGlzdG9yeSkKI2FwcGx5IE1JQ0UgaW1wdXRhdGlvbgpkZl9taWNlIDwtIG1pY2UoZGF0YTIsIG1ldGhvZCA9IGMoIiIsIiIsIiIsInBtbSIsInBvbHlyZWciLCJwbW0iLCIiLCIiLCIiKSwgIG0gPSAyMCwgbWF4aXQ9MjAsc2VlZCA9IDEyMywgcHJpbnQ9RikKCiMgQ29tcGxldGUgZGF0YXNldCB3aXRoIGltcHV0ZWQgdmFsdWVzCmRmX2ltcHV0ZWQgPC0gY29tcGxldGUoZGZfbWljZSkKCiNwbG90IGNvbXBhcmlzb25zIG9mIGJlZm9yZSBhbmQgYWZ0ZXIgTUlDRSBpbXB1dGF0aW9uIGZvciBoZWFydCBkaXNlYXNlCmcxIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IGltcHV0ZWRfbW9kZWhkKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiIzE1NDNhZCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNb2RlLWltcHV0ZWQiKSArCiAgbGFicyh4PSJIZWFydCBEaXNlYXNlIikrCiAgdGhlbWVfY2xhc3NpYygpCmcyIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IG9yaWdpbmFsKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiI2FkMTUzOCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCIpICsKICBsYWJzKHg9IkhlYXJ0IERpc2Vhc2UiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzMgPC0gZ2dwbG90KGRmX2ltcHV0ZWQsIGFlcyh4ID0gaGVhcnRfZGlzZWFzZSkpICsKICBnZW9tX2JhcihmaWxsID0gInB1cnBsZSIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNSUNFIikgKwogIGxhYnMoeD0iSGVhcnQgRGlzZWFzZSIpKwogIHRoZW1lX2NsYXNzaWMoKQpwbG90X2dyaWQoZzEsIGcyLCBnMywgbnJvdz0xLCBuY29sID0zKQpgYGAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJhciBncmFwaHMgc2hvdyB0aGUgY29tcGFyaXNvbiBvZiB0aGUgb3JpZ2luYWwgZGF0YSB0byBtb2RlIGltcHV0YXRpb24gYW5kIE1JQ0UuIE1JQ0UgYXBwZWFycyB0byBoYXZlIGRpc3BlcnNlZCB0aGUgZGF0YSBtb3JlIGV2ZW5seSBhY3Jvc3MgdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzLCB3aGlsZSBtb2RlIGltcHV0YXRpb24gaGFzIG9ubHkgYWRkZWQgdmFsdWVzIHRvICJuZXZlci4nfQojcGxvdCBjb21wYXJpc29ucyBmb3Igc21va2luZyBoaXN0b3J5Cmc0IDwtIGdncGxvdChkZl9pbXB1dGVkLCBhZXMoeCA9IHNtb2tpbmdfaGlzdG9yeSkpICsKICBnZW9tX2JhciggZmlsbCA9ICJwdXJwbGUiLCBjb2xvciA9ICIjMDAwMDAwIiwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiTUlDRSIpICsKICBsYWJzKHg9IlNtb2tpbmcgSGlzdG9yeSIpKwogIHRoZW1lX2NsYXNzaWMoKQpnNSA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBvcmlnaW5hbDIpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAicmVkIiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk9yaWdpbmFsIFNtb2tpbmcgSGlzdG9yeSIpICsKICBsYWJzKHg9IlNtb2tpbmcgSGlzdG9yeSIpKwogIHRoZW1lX2NsYXNzaWMoKQpnNiA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVzaCkpICsKICBnZW9tX2JhciggZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1vZGUtaW1wdXRlZCIpICsKICBsYWJzKHg9IlNtb2tpbmcgSGlzdG9yeSIpKwogIHRoZW1lX2NsYXNzaWMoKQpwbG90X2dyaWQoZzQsZzUsZzYsIG5yb3c9MywgbmNvbD0xKQpgYGAKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgYm94cGxvdHMgc2hvdyB0aGUgY29tcGFyaXNvbiBvZiB0aGUgb3JpZ2luYWwgZGF0YSB0byBib3RoIE1JQ0UgYW5kIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbi4nfQoKI3Bsb3QgY29tcGFyaXNvbnMgZm9yIGJtaQpnNzwtYm94cGxvdChkaWFiZXRlc2QkYm1pLAptYWluID0gIk1lYW4gYm1pIGluIE9yaWdpbmFsIERhdGEiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJibHVlIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc4IDwtYm94cGxvdChyZWdpbXB1dGUkYm1pLAptYWluID0gIlJlZ3Jlc3Npb24gSW1wdXRhdGlvbiBmb3IgQk1JIiwKeGxhYiA9ICJCTUkiLApjb2wgPSAicmVkIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc5IDwtYm94cGxvdChkZl9pbXB1dGVkJGJtaSwKbWFpbiA9ICJNSUNFIGZvciBCTUkiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJwdXJwbGUiLApib3JkZXIgPSAiYmxhY2siLApob3Jpem9udGFsID0gVFJVRSwKbm90Y2ggPSBUUlVFCikKCgoKYGBgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTV9Cm1vZGVsNSA8LSB3aXRoKGRmX21pY2UsIGxtKGRpYWJldGVzIH4gYm1pKyBoZWFydF9kaXNlYXNlKyBzbW9raW5nX2hpc3RvcnkgKSkKc3VtbWFyeShwb29sKG1vZGVsNSkpCmBgYAojIFNrZXduZXNzCgpTa2V3bmVzcyBpcyBhIG1lYXN1cmUgb2Ygc3ltbWV0cnkgd2l0aGluIGEgZGlzdHJpYnV0aW9uLiBUaGUgc2tld25lc3MgbWVhc3VyZW1lbnRzIGJlbG93IGFyZSBvZiB0aGUgdmFyaWFibGVzIGFnZSwgYm1pLCBIYkExYyBsZXZlbCwgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWwsIHJlc3BlY3RpdmVseS4gV2hlbiBza2V3bmVzcyBpcyBlcXVhbCB0byAwLCB3ZSBjYW4gYXNzdW1lIHRoZSBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBXaGVuIHNrZXduZXNzIGlzIGdyZWF0ZXIgdGhhbiAwLCBvdXIgZGF0YSBpcyBwb3NpdGl2ZWx5IHNrZXdlZCwgd2hpbGUgYSB2YWx1ZSBsZXNzIHRoYW4gemVybyBpbmRpY2F0ZXMgbmVnYXRpdmVseSBza2V3ZWQgZGF0YS4gRm9yIHRoZSBkaWFiZXRlcyBkYXRhc2V0LCB0aGUgdmFyaWFibGVzIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbCBhcmUgMSBvciBhYm91dCAxLCB3aGljaCBpbmRpY2F0ZSBhIHNpZ25pZmljYW50IHJpZ2h0IHNrZXcgaW4gdGhlIGRpc3RyaWJ1dGlvbi4gCmBgYHtyfQoKCgphZ2UxPC0gc2tld25lc3MoZGZfaW1wdXRlZCRhZ2UpIApibWkxPC1za2V3bmVzcyhkZl9pbXB1dGVkJGJtaSkgCkhiQTFjMTwtc2tld25lc3MoIGRmX2ltcHV0ZWQkSGJBMWNfbGV2ZWwpIApnbHVjb3NlMTwtc2tld25lc3MoZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsKQoKbXl0YWJsZTwtZGF0YS5mcmFtZShhZ2UxLGJtaTEsSGJBMWMxLCBnbHVjb3NlMSkKa2FibGUobXl0YWJsZSwgY2FwdGlvbj0gIlNrZXduZXNzIG9mIE51bWVyaWMgVmFyaWFibGVzIikKCmBgYAojIFRyYW5zZm9ybWluZyBEYXRhCgpUbyBoYW5kbGUgb3VyIHNrZXdlZCB2YXJpYWJsZXMsIHdlIGNhbiBub3JtYWxpemUgdGhlIHZhcmlhYmxlcyBibWkgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWwuIE5vcm1hbGl6YXRpb24gcmVzY2FsZXMgZGF0YSBpbnRvIGEgZml4ZWQgcmFuZ2Ugb2YgWzAsMV0uIEJ5IG5vcm1hbGl6aW5nIG91ciBkYXRhLCB3ZSBjYW4gZml4IHNrZXduZXNzIGFuZCBjcmVhdGUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YS4gVGhlIHZhcmlhYmxlcywgYWdlIGFuZCBIYkExYyBsZXZlbCBoYXZlIGJlZW4gc3RhbmRhcmRpemVkIHRvIGtlZXAgdGhlIGRpc3RyaWJ1dGlvbiBjZW50ZXJlZC4gU3RhbmRhcmRpemF0aW9uIGlzIHVzZWQgdG8gY3JlYXRlIGEgbWVhbiBvZiAwIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAxLCB0byBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uLiBCYXNlZCBvbiB0aGUgcmVzdWx0cyBiZWxvdywgd2UgY2FuIHNlZSB0aGF0IHRoZSB0cmFuc2Zvcm1hdGlvbiBoYXMgY29ycmVjdGVkIHRoZSByaWdodCBza2V3IGluIHRoZSBkYXRhIGZyb20gYmVmb3JlLgoKCmBgYHtyfQpkZl90cmFucyA8LSBkZl9pbXB1dGVkICAjIENvcHkgb3JpZ2luYWwgZGF0YXNldCBhZnRlciBNSUNFCgojZW5zdXJlIGRpYWJldGVzIGlzIG51bWVyaWMgYW5kIGEgZmFjdG9yCmRmX3RyYW5zJGRpYWJldGVzPC0gYXMubnVtZXJpYyhhcy5mYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMpKQojIE1pbi1NYXggTm9ybWFsaXphdGlvbgpub3JtYWxpemUgPC0gZnVuY3Rpb24oeCkgewogIGlmIChtYXgoeCkgLSBtaW4oeCkgPT0gMCkgcmV0dXJuKHJlcCgwLCBsZW5ndGgoeCkpKSAgIyBQcmV2ZW50IGRpdmlzaW9uIGJ5IHplcm8KICByZXR1cm4oKHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSkpCn0KCiNhcHBseSBub3JtYWxpemF0aW9uCmRmX3RyYW5zJGJtaSA8LSBub3JtYWxpemUoZGZfaW1wdXRlZCRibWkpCmRmX3RyYW5zJGJsb29kX2dsdWNvc2VfbGV2ZWwgPC0gbm9ybWFsaXplKGRmX2ltcHV0ZWQkYmxvb2RfZ2x1Y29zZV9sZXZlbCkKCiMgWi1TY29yZSBTdGFuZGFyZGl6YXRpb24Kc3RhbmRhcmRpemUgPC0gZnVuY3Rpb24oeCkgewogIHJldHVybigoeCAtIG1lYW4oeCwgbmEucm0gPSBUUlVFKSkgLyBzZCh4LCBuYS5ybSA9IFRSVUUpKQp9CgojYXBwbHkgc3RhbmRhcmRpemF0aW9uCmRmX3RyYW5zJGFnZSA8LSBzdGFuZGFyZGl6ZShkZl90cmFucyRhZ2UpCmRmX3RyYW5zJEhiQTFjX2xldmVsIDwtIHN0YW5kYXJkaXplKGRmX3RyYW5zJEhiQTFjX2xldmVsKQoKIyBBcHBseSBMb2cgVHJhbnNmb3JtYXRpb24gdG8gRml4IFNrZXduZXNzIChpZiBuZWNlc3NhcnkpCmRmX3RyYW5zJGJtaSA8LSBsb2cxcChkZl90cmFucyRibWkpICAjIGxvZygxICsgeCkgYXZvaWRzIGxvZygwKSBpc3N1ZXMKZGZfdHJhbnMkYmxvb2RfZ2x1Y29zZV9sZXZlbCA8LSBsb2cxcChkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsKQoKYm1pMiA8LSBza2V3bmVzcyhkZl90cmFucyRibWkpCmFnZTIgPC0gc2tld25lc3MoZGZfdHJhbnMkYWdlKQpIYkExYzI8LSBza2V3bmVzcyhkZl90cmFucyRIYkExY19sZXZlbCkKZ2x1Y29zZTI8LSBza2V3bmVzcyhkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsKQoKbmV3dGFibGU8LWRhdGEuZnJhbWUoYm1pMixhZ2UyLEhiQTFjMixnbHVjb3NlMikKa2FibGUobmV3dGFibGUsIGNhcHRpb249Ik5ld2x5IFRyYW5zZm9ybWVkIERhdGEiKQoKCmBgYApUcmFuc2Zvcm1pbmcgb3VyIGRhdGEgaGFzIHN1Y2Nlc3NmdWxseSBkZWNyZWFzZWQgc2tld25lc3MgaW4gb3VyIHZhcmlhYmxlcy4gV2UgY2FuIHNlZSBibWkgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWwgYXJlIG5vIGxvbmdlciBhYm91dCAxLiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nV2UgY2FuIHNlZSBpbiB0aGUgZ3JhcGhzIGFib3ZlIHRoYXQgYWZ0ZXIgdHJhbnNmb3JtaW5nIHRoZSBkYXRhc2V0LCB0aGUgZGF0YSBzZWVtcyB0byBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uIG1vcmUgY2xvc2VseS5UaGlzIGlzIGFwcGFyZW50IGluIHRoZSBoaXN0b2dyYW1zIGFwcGVhcmluZyBtb3JlIGluIGEgYmVsbCBzaGFwZSBjdXJ2ZS4nIH0KCiMgQ29tYmluZSBvbGQgYW5kIG5ldyBkYXRhIGZvciBjb21wYXJpc29uCmRmX2NvbXBhcmUgPC0gZGF0YS5mcmFtZSgKICBibWlfb3JpZ2luYWwgPSBkZl9pbXB1dGVkJGJtaSwKICBibWlfdHJhbnNmb3JtZWQgPSBkZl90cmFucyRibWksCiAgYmxvb2RfZ2x1Y29zZV9vcmlnaW5hbCA9IGRmX2ltcHV0ZWQkYmxvb2RfZ2x1Y29zZV9sZXZlbCwKICBibG9vZF9nbHVjb3NlX3RyYW5zZm9ybWVkID0gZGZfdHJhbnMkYmxvb2RfZ2x1Y29zZV9sZXZlbAopCgojIFJlc2hhcGUgZGF0YSBmb3IgZ2dwbG90CmRmX2xvbmcgPC0gbWVsdChkZl9jb21wYXJlKQoKIyBQbG90IGhpc3RvZ3JhbXMKZ2dwbG90KGRmX2xvbmcsIGFlcyh4ID0gdmFsdWUsIGZpbGwgPSB2YXJpYWJsZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhbHBoYSA9IDAuNiwgYmlucyA9IDMwLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJpc29uIG9mIE9yaWdpbmFsIHZzLiBUcmFuc2Zvcm1lZCBEYXRhIiwgeCA9ICJWYWx1ZSIsIHkgPSAiQ291bnQiKQoKCmBgYAoKCgoKIyBBbmFseXppbmcgRGF0YQpUaGUgbmV4dCBzdGVwIGlzIHRvIGZpbmQgd2hpY2ggdmFyaWFibGVzIGFyZSBzaWduaWZpY2FudGx5IGltcG9ydGFudCB3aGVuIHRyeWluZyB0byBwcmVkaWN0IGRpYWJldGVzLiBCeSB1c2luZyBmZWF0dXJlIHNlbGVjdGlvbiwgd2UgYXJlIGFibGUgdG8gcHJlZGljdCBwb3NzaWJsZSBiZXN0IGZpdCBtb2RlbHMgZm9yIG91ciB2YXJpYWJsZSwgZGlhYmV0ZXMuIEZvciB0aGlzIGRhdGEsIHdlIHdpbGwgZm9jdXMgb24gbG9naXN0aWMgcmVncmVzc2lvbi4gVGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgZGlhYmV0ZXMsIGlzIGEgYmluYXJ5IHZhcmlhYmxlIGluZGljYXRpbmcgbGluZWFyIHJlZ3Jlc3Npb24gd291bGQgbm90IG1ha2UgYW4gaWRlYWwgbW9kZWwuIAoKCgoqKlJhbmRvbSBGb3Jlc3QqKiAKRmlyc3QsIHdlIHdpbGwgbG9vayBhdCB0aGUgYmVzdCBtb2RlbCBzZWxlY3RlZCBieSBmZWF0dXJlIHNlbGVjdGlvbiB0aHJvdWdoIHJhbmRvbSBmb3Jlc3Q6CmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSxmaWcuY2FwPSdUaGUgdGFibGUgc2hvd3MgdGhlIHNlbGVjdGVkIHZhcmlhYmxlcyByYW5kb20gZm9yZXN0IGhhcyBzZWxlY3RlZCB0byB1c2UgZm9yIG91ciBtb2RlbC4nfQoKIyBQcmVwYXJlIHRoZSBkYXRhCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCgojIFNldCB1cCBSRkUgY29udHJvbCB3aXRoIHJhbmRvbSBmb3Jlc3QKY29udHJvbCA8LSByZmVDb250cm9sKGZ1bmN0aW9ucyA9IHJmRnVuY3MsIG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQoKIyBBcHBseSBSRkUgdG8gaWRlbnRpZnkgdG9wIGZlYXR1cmVzCnJlc3VsdHMgPC0gcmZlKAogIHggPSBkZl90cmFuc1ssICFjb2xuYW1lcyhkZl90cmFucykgJWluJSAiZGlhYmV0ZXMiXSwKICB5ID0gZGZfdHJhbnMkZGlhYmV0ZXMsCiAgc2l6ZXMgPSBjKDE6OSksCiAgcmZlQ29udHJvbCA9IGNvbnRyb2wKKQoKIyBQcmludCB0aGUgc2VsZWN0ZWQgZmVhdHVyZXMKbW9kZWxzPC1kYXRhLmZyYW1lKHByZWRpY3RvcnMocmVzdWx0cykpCmthYmxlKG1vZGVscywgY2FwdGlvbj0iUmFuZG9tIEZvcmVzdCBTZWxlY3RlZCBNb2RlbCIpCgoKYGBgCioqU3RlcHdpc2UgTG9naXN0aWMgUmVncmVzc2lvbioqCk5leHQsIGxldCdzIGxvb2sgYW5kIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGNvZWZmaWNpZW50cyBzaG93biBiZWxvdyBhcmUgdGhlIG9uZXMgc3RlcHdpc2UgbG9naXN0aWMgcmVncmVzc2lvbiBoYXMgY2hvc2VuIGZvciB0aGUgZmluYWwgbW9kZWwnfQojU3RlcHdpc2UgTG9naXN0aWMgUmVncmVzc2lvbgojIEZpdCBhIGZ1bGwgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGFsbCBwcmVkaWN0b3JzCmZ1bGxfbW9kZWwgPC0gZ2xtKGRpYWJldGVzIH4gLiwgZGF0YSA9IGRmX3RyYW5zLCBmYW1pbHkgPSBiaW5vbWlhbCkKCiMgUGVyZm9ybSBzdGVwd2lzZSBzZWxlY3Rpb24gKGRlZmF1bHQgaXMgYmFja3dhcmQgZWxpbWluYXRpb24pCnN0ZXBfbW9kZWwxIDwtIHN0ZXAoZnVsbF9tb2RlbCwgZGlyZWN0aW9uID0gImJvdGgiKQpzdW1tYXJ5KHN0ZXBfbW9kZWwxKQpgYGAKCkJvdGggc2VsZWN0aW9uIHR5cGVzIHNlbGVjdGVkIHRoZSBzYW1lIG1vZGVsISBIb3dldmVyIEkgd2lsbCBzdGlsbCBnbyB0aHJvdWdoIHRoZSBzdGVwcyBvZiBjcm9zcy12YWxpZGF0aW9uIGFzIHRob3VnaCBJIHdhcyBjb21wYXJpbmcgdGhlIHR3byBtb2RlbHMuCgojIENyb3NzLVZhbGlkYXRpb24KCkxldCdzIGV4cGxvcmUgY3Jvc3MtdmFsaWRhdGlvbiB0byBzZWUgd2hpY2ggbW9kZWwgaXMgYmVzdCBmaXQuIEZvciBsb2dpc3RpYyByZWdyZXNzaW9uLCBpdCBpcyBtZWFuaW5nZnVsIHRvIGxvb2sgYXQgYWNjdXJhY3kgYW5kIGthcHBhLiAKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01fQoKI2FkZCBjbGFzc2lmaWNhdGlvbgpkZl90cmFucyRkaWFiZXRlczwtIGZhY3RvcihpZmVsc2UoZGZfdHJhbnMkZGlhYmV0ZXM9PTEsICJZZXMiLCJObyIpKQoKdHJhaW5fY29udHJvbCA8LSB0cmFpbkNvbnRyb2woCiAgbWV0aG9kID0gImN2IiwgICAgICAgICAjIGNyb3NzLXZhbGlkYXRpb24KICBudW1iZXIgPSAxMCwgICAgICAgICAgICMgMTAtZm9sZAogIGNsYXNzUHJvYnMgPSBUUlVFICMgdXNlIGlmIHlvdSdyZSB0cmFja2luZyBBVUMsIFNlbnNpdGl2aXR5LCBldGMuCikKCiNydW4gQ1YgbW9kZWwKY3ZfbW9kZWwgPC0gdHJhaW4oCiAgZGlhYmV0ZXMgfiBoeXBlcnRlbnNpb24gKyBnZW5kZXIgK2FnZSArIEhiQTFjX2xldmVsICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIGhlYXJ0X2Rpc2Vhc2UgKyBibWksIAogIGRhdGE9ZGZfdHJhbnMsIAogIG1ldGhvZCA9ICJnbG0iLCAKICBmYW1pbHkgPSAiYmlub21pYWwiLCAKICB0ckNvbnRyb2wgPSB0cmFpbl9jb250cm9sCiAgKQoKcHJpbnQoY3ZfbW9kZWwpCgpgYGAKQWNjdXJhY3kgc2hvd3MgdGhlIG92ZXJhbGwgY29ycmVjdG5lc3Mgb2YgdGhlIG1vZGVsIHByZWRpY3Rpb25zIGFuZCBrYXBwYSBtZWFzdXJlcyB0aGUgbGV2ZWxzIG9mIGFncmVlbWVudCBiZXR3ZWVuIHZhcmlhYmxlcy4gVmFsdWVzIGNsb3NlciB0byAxIHN1Z2dlc3QgaGlnaGVyIGFjY3VyYWN5IGFuZCBiZXR0ZXIgYWdyZWVtZW50LiBUaGlzIG1vZGVsIHN1Z2dlc3RzIGhpZ2ggYWNjdXJhY3kgYW5kIGhpZ2ggYWdyZWVtZW50IGJhc2VkIG9uIHRoZSB2YWx1ZXMuCgojIFJPQyBDdXJ2ZSBhbmQgQU9DIEN1cnZlCgoqKkNvbmZ1c2lvbiBNYXRyaWNlcyoqClJPQyBpcyBhbHNvIGtub3duIGFzIFJlY2VpdmVyIE9wZXJhdGluZyBDaGFyYWN0ZXJpc3RpYyBBbmFseXNpcy4gSXQgaXMgYSB0ZWNobmlxdWUgdXNpbmcgZ3JhcGhzIHRoYXQgZXZhbHVhdGVzIHRoZSBwZXJmb3JtYW5jZSBvZiBhIGJpbmFyeSBtb2RlbC4gQmVmb3JlIHBsb3R0aW5nIHRoZSBST0MgY3VydmUsIGl0IGlzIG5lY2Vzc2FyeSB0byBjYWxjdWxhdGUgdGhlIHRydWUgcG9zaXRpdmUgcmF0ZSAoVFBSKSBhbmQgZmFsc2UgcG9zaXRpdmUgcmF0ZSAoRlBSKS4gQmVsb3csIGFyZSBjb25mdXNpb24gbWF0cmljZXMgdGhhdCB3ZXJlIHVzZWQgdG8gY2FsY3VsYXRlIHRob3NlIHZhbHVlcy4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCdUaGVzZSBtYXRyaWNlcyBhcmUgdXNlZCB0byBjYWxjdWxhdGUgVFBSIGFuZCBGUFIuIFRoZXNlIHZhbHVlcyBhcmUgdXNlZCB0byBjcmVhdGUgdGhlIFJPQyBjdXJ2ZS4nfQoKI1JPQyBhbmQgQVVDCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCiMgZml0IGEgbG9naXN0aWMKbW9kZWwubG9naXQgPC0gZ2xtKGRpYWJldGVzIH4gYWdlICsgZ2VuZGVyKyBibWkraHlwZXJ0ZW5zaW9uICsgaGVhcnRfZGlzZWFzZSArIGJsb29kX2dsdWNvc2VfbGV2ZWwrIEhiQTFjX2xldmVsICwgZmFtaWx5ID0gYmlub21pYWwsIGRhdGEgPSBkZl90cmFucykKIyBwcmVkaWN0IHByb2JhYmlsaXR5IG9mIFAoWSA9ICJZZXMiKQpwcm9iYWJpbGl0aWVzIDwtIHJvdW5kKGFzLnZlY3RvcihwcmVkaWN0KG1vZGVsLmxvZ2l0LCB0eXBlID0gInJlc3BvbnNlIikpLDMpCiMKdGhyZXNob2xkcyA8LSBjKDAuMCwgMC4yNSwgMC41LCAwLjc1LCAxLjApCgojIExvb3AgdGhyb3VnaCB0aHJlc2hvbGRzIGFuZCBjcmVhdGUgY29uZnVzaW9uIG1hdHJpY2VzCmZvciAodGhyZXNob2xkIGluIHRocmVzaG9sZHMpIHsKICBjYXQoIlxuQ29uZnVzaW9uIE1hdHJpeCBmb3IgVGhyZXNob2xkID0iLCB0aHJlc2hvbGQsICJcbiIpCiAgCiAgIyBDb252ZXJ0IHByb2JhYmlsaXRpZXMgdG8gcHJlZGljdGlvbnMKICAjIGFtOiAxID0gbWFudWFsIHRyYW5zbWlzc2lvbiwgMCA9IGF1dG9tYXRpYyB0cmFuc21pc3Npb24KICBwcmVkaWN0aW9ucyA8LSBpZmVsc2UocHJvYmFiaWxpdGllcyA+IHRocmVzaG9sZCwgIlllcyIsICJObyIpCiAgICBhbGxfbGV2ZWxzIDwtIHVuaW9uKGxldmVscyhmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMpKSwgbGV2ZWxzKGZhY3RvcihwcmVkaWN0aW9ucykpKQogICAgIyBHZW5lcmF0ZSBjb25mdXNpb24gbWF0cml4CiAgY20gPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihwcmVkaWN0aW9ucywgbGV2ZWxzPWFsbF9sZXZlbHMpLCBmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMsbGV2ZWxzPWFsbF9sZXZlbHMpLCBwb3NpdGl2ZSA9ICJZZXMiKQogIHByaW50KGNtJHRhYmxlKQp9CgpgYGAKKipST0MgQ3VydmUqKgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsJ1RoZSBwbG90IHNob3dzIHRoZSBwYXRoIG9mIHRoZSBST0MgY3VydmUuJ30KCiNjcmVhdGUgUk9DIGN1cnZlCgpUUFIgPSBjKDEsOTE1MDAvKDkxNTAwKzApLCA5MTM1Ni8oOTEzNTYrMTQ0KSwgOTA2MzIvKDkwNjMyKzg2OCksIDg4MTYwLyg4ODE2MCszMzQwKSwgMC8oOTE1MDArMCkpCkZQUiA9IGMoMSwzNTIvKDM1Mis4MTQ4KSwgNDI4Mi8oNDI4Mis0MjE4KSwgMzE5My8oNTMwNyszMTkzKSwgMjE3OC8oMjE3OCs2MzIyKSwgMC8oODUwMCswKSkKcGxvdChGUFIsIFRQUiwgdHlwZSA9ICJiIiwgbWFpbiA9ICJBbiBJbGx1c3RyYXRpdmUgUk9DIEN1cnZlIiwgY29sID0iYmx1ZSIsCiAgICAgeGxhYj0iMSAtIFNwZWNpZml0eSAoRlBSKSIsIHlsYWIgPSAiU2Vuc2l0aXZpdHkgKFRQUikiKQojIGFkZCBhIG9mZi1kaWFnb25hbCByZXByZXNlbnRpbmcgcmFuZG9tIGd1ZXNzIGFsZ29yaXRobSBpbiBiaW5hcnkgcHJlZGljdGlvbgphYmxpbmUoMCwxLCBsdHkgPSAyLCBjb2wgPSAicmVkIikKIyBsZWdlbmQKbGVnZW5kKCJib3R0b21yaWdodCIsIGMoIkxvZ2lzdGljIE1vZGVsIiwgIlJhbmRvbSBHdWVzcyIpLAogICAgICAgY29sPWMoImJsdWUiLCAicmVkIiksIGx0eSA9IDE6MiwgYnR5PSJuIiwgY2V4ID0gMC45KQpgYGAKKipBVUMgKEFyZWEgdW5kZXIgdGhlIEN1cnZlKSoqCkFVQyBxdWFudGlmaWVzIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgUk9DIGN1cnZlIGludG8gYSBzaW5nbGUgdmFsdWUgdGhhdCByYW5nZXMgZnJvbSAwIHRvIDEuIFRoZSBwbG90IGJlbG93IHVzZXMgdGhlIFJpZW1hbm4gU3VtIGFwcHJveGltYXRpb24gdG8gZXN0aW1hdGUgdGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlLgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsJ1RoZSBwbG90IGVzdGltYXRlcyB0aGUgYXJlYSBvZiB0aGUgUk9DIEN1cnZlLiBUaGUgcmVnaW9uIGlzIGRpdmlkZWQgaW50byBzdWJyZWdpb25zLCBBLEIsIGFuZCBDLiBUaGVzZSB2YWx1ZXMgYXJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZS4nIH0KI0FVQwpUUFIgPSByb3VuZChjKDEsOTE1MDAvKDkxNTAwKzApLCA5MTM1Ni8oOTEzNTYrMTQ0KSwgOTA2MzIvKDkwNjMyKzg2OCksIDg4MTYwLyg4ODE2MCszMzQwKSwgMC8oOTE1MDArMCkpLDMpCkZQUiA9IHJvdW5kKGMoMSwzNTIvKDM1Mis4MTQ4KSwgNDI4Mi8oNDI4Mis0MjE4KSwgMzE5My8oNTMwNyszMTkzKSwgMjE3OC8oMjE3OCs2MzIyKSwgMC8oODUwMCswKSksMykKVFBSMCA9IFRQUls3OjFdCkZQUjAgPSBGUFJbNzoxXQojcGxvdChGUFIwLCBUUFIwLCB0eXBlID0gImIiKQpkYXRTZW5TcGUgPSBkYXRhLmZyYW1lKFRQUjAsIEZQUjApCmdnUk9DID0gZ2dwbG90KGRhdGEgPSBkYXRTZW5TcGUsIGFlcyh4ID0gRlBSMCwgeT1UUFIwKSkgKwogICAgICAgIGdlb21fbGluZShjb2wgPSAic3RlZWxibHVlIikgKwogICAgICAgIGdlb21fcG9pbnQoY29sID0gInJlZCIpICsKICAgICAgICBnZW9tX3NlZ21lbnQoeCA9IEZQUjAsIHkgPSAwLCB4ZW5kID0gRlBSMCwgeWVuZCA9IFRQUjAsIGNvbG9yID0gNCkgKwogICAgICAgIGdlb21fc2VnbWVudCh4ID0gMCwgeSA9IDAsIHhlbmQgPSBGUFIwWzddLCB5ZW5kID0gMCwgY29sb3IgPSA2KSArCiAgICAgICAgZ2d0aXRsZSgiQXBwcm94aW1hdGluZyB0aGUgQVVDIG9mIExvZ2lzdGljIE1vZGVsIikgKwogICAgICAgIHhsYWIoIjEtc3BlY2lmaWNpdHkgKEZQUikiKSArIAogICAgICAgIHlsYWIoIlNlbnNpdGl2aXR5IChUUFIpIikgKwogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuMDI1LCB5ID0gMC4xMjUsIGxhYmVsPSAiQSIpICsgCiAgICAgICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMC4xMDUsIHkgPSAwLjUsIGxhYmVsID0gIkIiKSArCiAgICAgICAgYW5ub3RhdGUoInRleHQiLCB4ID0gMC42MDUsIHkgPSAwLjUsIGxhYmVsID0gIkMiKSArCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsIDAuMiksCiAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC4xNSwgMC4xNSwgMC43NSwgMC4xNSksICJpbmNoZXMiKSwKICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDIsIGNvbG91ciA9ICJuYXZ5IiwgbGluZXR5cGU9MSkpCiMgcGFydGl0aW9uIHRoZSByZWdpb24gdW5kZXIgdGhlIFJPQyBpbnRvIHRyYXBlem9pZHMKZ2dwbG90bHkoZ2dST0MpCmBgYAoKKipBVUMgVmFsdWUqKgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsJ1RoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBpcyAwLjk3OTUgd2hpY2ggaXMgY2xvc2UgdG8gMSwgdGhpcyBpbmRpY2F0ZXMgYW4gaWRlYWwgbW9kZWwuJ30KQTwtKDAuMDQxKjEpLzIKQjwtICgoMC41MDQtMC4wNDEpKjEpCkM8LSAoKDEtMC41MDQpKjEpCgpBVUM8LSBBK0IrQwprYWJsZShBVUMsIGNhcHRpb249ICJBcmVhIHVuZGVyIHRoZSBDdXJ2ZSIpCgpgYGAKIyBDb25jbHVzaW9uIGZvciBNb2RlbCBGaXQKT3VyIGJlc3QgZml0IG1vZGVsIGlzIDoKJCQKXHRleHR7IERpYWJldGVzfSA9IDkuOTkgLSAwLjI3XHRpbWVzIFx0ZXh0e2dlbmRlcn0gLSAxLjAzXHRpbWVzIFx0ZXh0e2FnZX0gIC0wLjhcdGltZXMgXHRleHR7aHlwZXJ0ZW5zaW9ufSAtIDAuNzZcdGltZXMgXHRleHR7aGVhcnQgZGlzZWFzZX0gLTEwLjI0XHRpbWVzIFx0ZXh0e2JtaX0gLSAyLjQ5XHRpbWVzIFx0ZXh0e0hiQTFjIGxldmVsfSAtIC0xMC4zXHRpbWVzIFx0ZXh0e2Jsb29kIGdsdWNvc2UgbGV2ZWx9CiQkCgoKVGhlIGJlc3QgZml0IG1vZGVsIHdhcyBzZWxlY3RlZCBiYXNlZCBvbiBhIHZhcmlldHkgb2YgZGlmZmVyZW50IGZlYXR1cmVzLiBCb3RoIHN0ZXB3aXNlIHNlbGVjdGlvbiBhbmQgcmFuZG9tIGZvcmVzdCBzZWxlY3RlZCB0aGUgbW9kZWwgYXMgYmVzdCBmaXQuIEFmdGVyIHJ1bm5pbmcgcGVyZm9ybWFuY2UgYW5hbHlzZXMgb24gdGhlIG1vZGVsLCB0aGUgbW9kZWwgd2FzIHNob3duIHRvIGJlIG9mIGhpZ2ggcGVyZm9ybWFuY2UuIFRoaXMgbWVhbnMgdGhhdCB0aGUgdmFyaWFibGVzIGNob3NlbiBmb3IgdGhlIGZpbmFsIG1vZGVsIGFyZSBzaWduaWZpY2FudCBmb3IgcHJlZGljdGluZyBkaWFiZXRlcy4gVGhlIG1vZGVsIGNob3NlIG5vdCB0byBzZWxlY3Qgc21va2luZyBoaXN0b3J5IGFzIHNpZ25pZmljYW50IHByZWRpY3RvciBmb3IgdGhlIHJlc3BvbnNlIHZhcmlhYmxlLiBBIHBvc3NpYmxlIHN1Z2dlc3Rpb24gZm9yIHRoaXMgd291bGQgYmUgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgcmVzcG9uc2UgdmFsdWVzIHRvIGEgYmluYXJ5IHJlc3BvbnNlLiBTdWNoIGFzLCAiSGF2ZSB5b3UgZXZlciBzbW9rZWQ/IiBhbmQgaGF2ZSB0aGUgcmVzcG9uc2UgYmUgIlllcyIgb3IgIk5vIi4gVGhpcyBjb3VsZCBoZWxwIGluIHByZWRpY3RpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNtb2tpbmcgYW5kIGRpYWJldGVzLiAK